import multiprocessing
import os
import re
import subprocess
import sys
from typing import List

import requests
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt, QThread
from PyQt5.QtGui import QCursor, QIcon, QColor
from PyQt5.QtWidgets import QApplication, QListWidgetItem, QMessageBox, QMenu, QAction

from browser import Browser
# from form import Ui_MainWindow
from ui_form import Ui_MainWindow
from myjob import DownloadThread, ParseThread, MergeThread


class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.thread = None
        self.download_thread = None
        self.merge_thread = None
        self.my_request_thread = None
        self.audio_thread = None
        self.video_thread = None
        self.parse_video_urls_return: str = None  # 接收线程解析结果

        self.setupUi(self)

        # 请求头
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76",
            "Referer": "https://www.bilibili.com/",
        }

        # 解析结果
        self.parse_result = []  # (title, video_url, audio_url)
        # 待下载列表
        self.download_list = []  # (title, video_url, audio_url)

        # 创建 MyLogin 实例
        self.my_login = MyLogin()
        # 登录界面，将 MyLogin 界面显示绑定在 pushButtonLogin 按钮上
        self.pushButton_login.clicked.connect(self.show_my_login)

        # 绑定信号槽
        self.pushButton_3.clicked.connect(self.start_parse)

        # 绑定下载按钮
        self.pushButton_4.clicked.connect(self.start_download)

        # 合并按钮
        self.pushButton_5.clicked.connect(self.start_merge)

        # 绑定搜索槽函数
        self.pushButton.clicked.connect(self.search_by_keyword)

        # 绑定搜索槽函数
        self.pushButton_clear.clicked.connect(self.clear)

        # 绑定打开输出路径按钮
        self.pushButton_6.clicked.connect(self.open_out_folder)

        # 声明在groupBox创建右键菜单
        self.listWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.listWidget.customContextMenuRequested.connect(self.create_rightmenu)  # 连接到菜单显示函数

        # 绑定全选按钮
        self.checkBox_selectAll.stateChanged.connect(self.selectDeselectAll)

    def selectDeselectAll(self, state):
        if state == 2:  # 选中状态
            self.listWidget.selectAll()
            self.checkBox_selectAll.setText("取消全选")
        else:
            self.listWidget.clearSelection()
            self.checkBox_selectAll.setText("全选")

    def create_rightmenu(self):
        # 菜单对象
        self.groupBox_menu = QMenu(self)
        self.action_download = QAction(QIcon('image/favicon.ico'), u'加入下载队列', self)
        self.action_download.setShortcut(Qt.Key_D)  # 设置快捷键
        self.groupBox_menu.addAction(self.action_download)  # 添加到菜单
        self.action_download.triggered.connect(self.action_download_func)  # 将下载动作设置信号槽

        self.groupBox_menu.popup(QCursor.pos())  # 声明当鼠标在groupBox控件上右击时，在鼠标位置显示右键菜单 exec_,popup两个都可以。

    def action_download_func(self):

        # 清空下载列表
        self.download_list.clear()

        # 获取当前多选值
        texts = self.listWidget.selectedItems()

        # 设置字体颜色为绿色
        for item in texts:
            item.setForeground(QColor('green'))

        texts = [i.text() for i in texts]

        # 添加到待下载列表中
        for row in self.parse_result:
            for text in texts:
                if text == row[0]:
                    title = row[0]
                    video_url = row[1]
                    audio_url = row[2]
                    self.download_list.append((title, video_url, audio_url))

        # print(*[i[0] for i in self.download_list])

    def open_out_folder(self):
        command = f'explorer out'
        subprocess.call(command, shell=False)

    def show_my_login(self):
        # 显示登录界面
        self.my_login.show()

    def start_download(self):
        # 判空
        if not self.download_list:
            QMessageBox.question(self, "提示", "请解析或搜索后选中下载项目，并加入下载列表！", QMessageBox.Yes)

            return

        # PyQt线程科学用法
        self.thread = QThread()
        # 实例外线程对象 workThread是自己写的线程类，后面会贴出来
        self.download_thread = DownloadThread(self)
        # 把实例化的线程用moveToThread移到QThread管理
        self.download_thread.moveToThread(self.thread)

        # 线程开始执行之前，从相关线程发射信号
        self.thread.started.connect(self.download_thread.run)

        # 绑定视频下载函数，刷新进度条
        self.download_thread.progress_video.connect(self.flush_download_video_progress)
        # 绑定音频下载函数，刷新进度条
        self.download_thread.progress_audio.connect(self.flush_download_audio_progress)
        # 绑定完成函数
        self.download_thread.progress_finish.connect(self.end_download)

        # 线程执行完成关闭线程
        self.thread.finished.connect(self.thread.quit)
        # 启动线程
        self.thread.start()

    def end_download(self, title):
        self.statusbar.showMessage(f"{title} 下载完成")

        # 退出线程
        self.thread.quit()

    def flush_download_video_progress(self, value):
        self.progressBar.setValue(value)

    def flush_download_audio_progress(self, value):
        self.progressBar_3.setValue(value)

    def start_merge(self):
        # 判断任务是否已经开始
        if self.merge_thread is not None:
            return

        list_item = QListWidgetItem()
        list_item.setText('合并任务开始...')
        self.listWidget.addItem(list_item)

        # 创建线程
        self.merge_thread = MergeThread()
        # 绑定进度条信号槽
        self.merge_thread.progress.connect(self.update_merge_progress)
        self.merge_thread.start()  # 开始合并！

    def update_merge_progress(self, value: int):
        # 取整
        value = int(min(value, 100))

        # 全部任务结束
        if value == 100:
            list_item = QListWidgetItem()
            list_item.setText('合并任务完成')
            self.listWidget.addItem(list_item)
            self.merge_thread = None

        # 刷新进度条
        self.progressBar_4.setValue(value)
        return

    def end_request(self):

        print("解析完成")

    def start_parse(self, urls: list):

        # 刷新设置cookies
        self.headers['cookie'] = '; '.join([f'{name}={value}' for name, value in self.my_login.cookies.items()])
        # 定义一个局变量
        title = None

        if urls == 0:
            # 获取链接
            url = self.lineEdit_2.text()
            urls = [url]

        try:
            # 创建线程下载
            self.my_request_thread = ParseThread(urls, self)
            # 连接槽函数
            self.my_request_thread.finished.connect(self.end_request)
            # 启动线程
            self.my_request_thread.start()

            return

        except BaseException as error:
            list_item = QListWidgetItem()
            list_item.setText(f'状态：解析失败！')
            self.listWidget.addItem(list_item)
            print("解析失败", error)
            return

    def search_by_keyword(self) -> List[str]:

        # 获取搜索关键字
        keyword = self.lineEdit.text()
        # 获取搜索数量
        search_num = int(self.comboBox.currentText())

        # 请求参数
        params = {
            '__refresh__': 'true',
            '_extra': '',
            'context': '',
            'page': 0,
            'page_size': search_num,
            'from_source': '',
            'from_spmid': '333.337',
            'platform': 'pc',
            'highlight': '1',
            'single_column': '0',
            'keyword': keyword,
            'category_id': '',
            'search_type': 'video',
            'dynamic_offset': 24,
            'preload': 'true',
            'com2co': 'true',
        }

        url = r'https://search.bilibili.com/all'
        res = requests.get(url, headers=self.headers, params=params)
        res.encoding = 'utf-8'
        pattern = '(?<=bvid:")[a-zA-Z\d]+(?=")'
        re_obj = re.compile(pattern)
        urls = re_obj.findall(res.text)

        urls = list(set(urls))[:search_num]  # 控制解析数量

        urls = [f'https://www.bilibili.com/video/{i}/' for i in urls]  # 拼接url

        # 搜索后解析
        self.start_parse(urls)

    def clear(self):
        self.lineEdit.clear()
        self.lineEdit_2.clear()
        self.listWidget.clear()
        self.parse_result.clear()
        self.download_list.clear()
        self.progressBar.setValue(0)
        self.progressBar_3.setValue(0)
        self.progressBar_4.setValue(0)


class MyLogin(Browser):
    def __init__(self):
        super().__init__()


def create_directories(dir_name):
    out_dir = dir_name
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)


def main():
    multiprocessing.freeze_support()

    create_directories("tempfolder")
    create_directories("out")

    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    # pyuic5 -o ui_form.py form.ui
    main()
